package com.iot08.admin.workTask;

import com.alibaba.fastjson.JSONObject;
import com.iot08.admin.service.*;
import com.iot08.admin.utils.ExcelUtil;
import com.iot08.common.config.redis.RedisService;
import com.iot08.common.constant.Const;
import com.iot08.common.entity.admin.SysUser;
import com.iot08.common.entity.app.Device;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.util.*;

/**
 * @author weichao 1299101858@qq.com
 * @version 1.0
 * @date 2021-09-28 18:09
 */
@Slf4j
public class DevResetWorkTask extends Thread  {


    private OperationService operationService;

    private NotifyService notifyService;

    private UserService userService;

    private ChannelAreaService channelAreaService;

    private String importPath;

    private Set<String> set;

    private List<Long> excludeAgent;

    private MongoTemplate mongoTemplate;

    private SysUser user;

    private String ip;

    private String filename;

    private RedisService redisService;

    //任务ID
    private String workId;

    //
    public DevResetWorkTask(OperationService operationService,
                            NotifyService notifyService,
                            UserService userService,
                            ChannelAreaService channelAreaService,
                            String importPath,
                            Set<String> set,
                            List<Long> excludeAgent,
                            MongoTemplate mongoTemplate,
                            SysUser user,
                            String ip,
                            String filename,
                            RedisService redisService,
                            String workId) {

        this.operationService = operationService;
        this.notifyService = notifyService;
        this.userService = userService;
        this.channelAreaService = channelAreaService;
        this.importPath = importPath;
        this.set = set;
        this.excludeAgent = excludeAgent;
        this.mongoTemplate = mongoTemplate;
        this.user = user;
        this.ip = ip;
        this.filename = filename;
        this.redisService = redisService;
        this.workId = workId;
    }

    @Override
    public void run() {
        String notUnbindExcelUrl = "";
        Query query = new Query();
        Criteria criteria = Criteria.where("_id").in(set);
        if (user.getType() == Const.CHANNELUSER_TYPE) {
            if (user.getChannelArea() != null) {
                List<String> areaIdList = channelAreaService.listIdById(user.getChannelAreaId(), true);
                criteria.and("channel_area_id").in(areaIdList);
            }
            //渠道账号，获取所拥有的渠道
            criteria.orOperator(Criteria.where("agent").in(user.getChannelAff().getChannelCodes()),
                    Criteria.where("agent").in(excludeAgent),
                    Criteria.where("agent").exists(false));
        }

        query.addCriteria(criteria);
        query.fields().include("_id");
//        List<String> imeiList = new ArrayList<>();
        List<Device> list = mongoTemplate.find(query, Device.class);

        //进度对象
        JSONObject speedOfProgressOB = new JSONObject();
        //解绑总数
        speedOfProgressOB.put("count", list.size());

        //挂失数组
        Set<String> lossDevResetFailSet = new HashSet<>();
        //失败数组
        Set<String> resetFailSet = new HashSet<>();
        if (list.size() > 0) {
            //可解绑到的
            for (int i = 0; i < list.size(); i++) {
                if (list.get(i) == null) {
                    continue;
                }
                //解绑通知
                Device temDev = list.get(i);
                JSONObject res = notifyService.deviceReset(temDev.getId(), "WEB:" + user.getId(), false, user);

                if(res != null){
                    log.info("WEB 调用 API 进行恢复出厂设置解绑(不能解绑挂失) res:{} ",res.toJSONString());
                    if(res.getInteger("code") == 0){
                        // 解绑成功, 移除set
                    }else if(res.getInteger("code") == 6001){
                        // 是挂失的表,解绑失败, 也移除,然后加到一个新数组内

                        lossDevResetFailSet.add(temDev.getId());
                    }else{
                        // 解绑失败, 也移除,然后加到一个新数组内
                        resetFailSet.add(temDev.getId());
                    }
                    set.remove(temDev.getId());
                }
                //当前解绑进度, 每10个更新一次 或最后一次时
                if(i % 10 == 0 || i == list.size() - 1 ){
                    speedOfProgressOB.put("index", i+1);
                    redisService.set(workId, speedOfProgressOB.toJSONString());
                    log.info("操作者:{} workId:{} 解绑进度:{}%%", user.getId(), workId, ( (i+1) *1.0/list.size()) * 100);
                }


            }
        }
        String down_url = "../device/downloadExcel?type=2";
        //无效号码
        int invalidNum = set.size();
        //失败的
        int failNum = resetFailSet.size();
        //因挂失中 失败的
        int lossNum = lossDevResetFailSet.size();
        //成功的 因为list 中的全部有效的所以不包含无效的
        int successNum = list.size()-failNum-lossNum;
        //set 中还剩下的就是无效的imei(在数据库中找不到)   lossDevResetFailSet解绑失败,在挂失中的   resetFailSet其他情况解绑失败的
        if (set.size() > 0 || lossDevResetFailSet.size() > 0 || resetFailSet.size() > 0) {

            Workbook notDelExcel = new XSSFWorkbook();
            Sheet notFoundSheet = notDelExcel.createSheet();
            //第一行
            Row fristRow = notFoundSheet.createRow(0);
            //imei 列 (0)
            Cell item0 = fristRow.createCell(0);
            ExcelUtil.setCellValue(item0, "imei 号");

            //原因 列 (1)
            Cell item1 = fristRow.createCell(1);
            ExcelUtil.setCellValue(item1, "原因");
            int index = 1;
            for (String notDelId : set) {
                Row row = notFoundSheet.createRow(index);
                //imei 列 (0)
                Cell imeiCell = row.createCell(0);
                ExcelUtil.setCellValue(imeiCell, notDelId);

                //原因 列 (1)
                Cell reasonCell = row.createCell(1);
                ExcelUtil.setCellValue(reasonCell, "无效imei号");
                index++;
            }

            for (String item : lossDevResetFailSet ) {
                Row row = notFoundSheet.createRow(index);
                //imei 列 (0)
                Cell imeiCell = row.createCell(0);
                ExcelUtil.setCellValue(imeiCell, item);

                //原因 列 (1)
                Cell reasonCell = row.createCell(1);
                ExcelUtil.setCellValue(reasonCell, "设备挂失中,无法解绑");
                index++;
            }

            for (String item : resetFailSet ) {
                Row row = notFoundSheet.createRow(index);
                //imei 列 (0)
                Cell imeiCell = row.createCell(0);
                ExcelUtil.setCellValue(imeiCell, item);

                //原因 列 (1)
                Cell reasonCell = row.createCell(1);
                ExcelUtil.setCellValue(reasonCell, "可能imei号不属于您 或 解绑错误");
                index++;
            }

            try {
                notUnbindExcelUrl = importPath + File.separator + user.getId() + "-not_unbind.xlsx";
                FileOutputStream notUnbindFile = new FileOutputStream(notUnbindExcelUrl);
                notDelExcel.write(notUnbindFile);
                notUnbindFile.close();
            }catch (Exception error){
                log.error("notUnbindExcelUrl 保存报错:"+error.getMessage(), error);
            }


            speedOfProgressOB.put("showMsg", String.format("成功解绑%s个设备号，无效的%s个,不成功%s个,因挂失解绑失败的%s个", successNum, invalidNum, failNum, lossNum));
            speedOfProgressOB.put("down_url", down_url);
        } else {
            speedOfProgressOB.put("showMsg", String.format("成功解绑%s个设备号", list.size()-set.size()));
        }
        speedOfProgressOB.put("success", 1);
        //设置结果保存7天
        redisService.setex(workId, 7 * 60*60*24, speedOfProgressOB.toJSONString());
//        Map<String, Object> map = new HashMap<>();
//        map.put("msg", msg);
//        map.put("notUnbindExcelUrl", notUnbindExcelUrl);

        //只有 真正有效的解绑
        if (list.size() > 0) {
            if (Const.CHANNELUSER_TYPE == user.getType()) {
                //更新解绑数量
                userService.updateTodayUnbindNum(user.getId(), list.size());
            }
            String desStr = String.format("成功解绑%s个设备号，无效的%s个,不成功%s个,因挂失解绑失败的%s个", successNum, invalidNum, failNum, lossNum);
            if(StringUtils.isNotEmpty(notUnbindExcelUrl)){
                desStr = String.format("成功解绑%s个设备号，无效的%s个,不成功%s个,因挂失解绑失败的%s个, 不成功的下载文件(只会保留最新的不成功文件)URL:%s",
                        successNum, invalidNum, failNum, lossNum, down_url);
            }

            //添加操作记录
            operationService.add(user, ip, Const.OPERATION_DELETE, "设备解绑",
                    null, "多个解绑", desStr, null, filename, null);
        }
    }
}
